﻿namespace PmSoft.Core.Extensions;

/// <summary>
/// DateTime 扩展方法
/// </summary>
public static class DateTimeExtensions
{
	/// <summary>
	/// 获取日期的起始时间
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>日期的起始时间</returns>
	public static DateTime GetStartOfDay(this DateTime? dateTime)
	{
		if (!dateTime.HasValue)
			return DateTime.Now.Date;
		return dateTime.Value.GetStartOfDay();
	}

	/// <summary>
	/// 获取日期的起始时间
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>日期的起始时间</returns>
	public static DateTime GetStartOfDay(this DateTime dateTime)
	{
		return dateTime.Date;
	}

	/// <summary>
	/// 获取日期的结束时间
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>日期的结束时间</returns>
	public static DateTime GetEndOfDay(this DateTime? dateTime)
	{
		if (!dateTime.HasValue)
			return DateTime.Now;
		return dateTime.Value.GetEndOfDay();
	}

	/// <summary>
	/// 获取日期的结束时间
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>日期的结束时间</returns>
	public static DateTime GetEndOfDay(this DateTime dateTime)
	{
		return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59);
	}

	/// <summary>
	/// 与当前时间的差值（分钟）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>差值（分钟）</returns>
	public static int GetDifferenceInMinutes(this DateTime? dateTime)
	{
		if (!dateTime.HasValue)
			return 0;
		return dateTime.Value.GetDifferenceInMinutes();
	}

	/// <summary>
	/// 与当前时间的差值（分钟）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>差值（分钟）</returns>
	public static int GetDifferenceInMinutes(this DateTime dateTime)
	{
		TimeSpan ts1 = new TimeSpan(dateTime.Ticks);
		TimeSpan ts2 = new TimeSpan(DateTime.Now.Ticks);
		TimeSpan ts = ts1.Subtract(ts2).Duration();
		return (int)ts.TotalMinutes;
	}

	/// <summary>
	/// 转换为剩余时间
	/// </summary>
	/// <param name="deadline">截止日期</param>
	/// <returns>剩余时间</returns>
	public static string GetTimeLeft(this DateTime? deadline)
	{
		if (!deadline.HasValue) return "N/A";
		return deadline.Value.GetTimeLeft();
	}

	/// <summary>
	/// 转换为剩余时间
	/// </summary>
	/// <param name="deadline">截止日期</param>
	/// <returns>剩余时间</returns>
	public static string GetTimeLeft(this DateTime deadline)
	{
		if (deadline == null) return "N/A";
		int totalSeconds = (int)deadline.Subtract(DateTime.Now).TotalSeconds;
		TimeSpan ts = new TimeSpan(0, 0, totalSeconds);
		if (ts.Days > 0)
		{
			return ts.Days.ToString() + "天";
		}
		if (ts.Days == 0 && ts.Hours > 0)
		{
			return ts.Hours.ToString() + "小时 ";
		}
		if (ts.Days == 0 && ts.Hours == 0 && ts.Minutes > 0)
		{
			return ts.Minutes.ToString() + "分钟 ";
		}
		return "N/A";
	}

	/// <summary>
	/// 格式化为（月/日）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToMonthDayString(this DateTime? dateTime)
	{
		if (dateTime.HasValue)
			return dateTime.Value.ToMonthDayString();
		else
			return "N/A";
	}

	/// <summary>
	/// 格式化为（月/日）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToMonthDayString(this DateTime dateTime)
	{
		return dateTime.ToString("MM/dd");
	}

	/// <summary>
	/// 格式化为中文（月日）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <param name="defaultValue">默认值</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToMonthDayStringChinese(this DateTime? dateTime, string defaultValue = "N/A")
	{
		if (!dateTime.HasValue)
		{
			return defaultValue;
		}
		return dateTime.Value.ToString("MM月dd日");
	}

	/// <summary>
	/// 格式化为中文（月日）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToMonthDayStringChinese(this DateTime dateTime)
	{
		return dateTime.ToString("MM月dd日");
	}

	/// <summary>
	/// 格式化为中文（年月）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <param name="defaultValue">默认值</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToYearMonthStringChinese(this DateTime? dateTime, string defaultValue = "N/A")
	{
		if (!dateTime.HasValue)
		{
			return defaultValue;
		}
		return dateTime.Value.ToString("yyyy年MM月");
	}

	/// <summary>
	/// 标准格式（yyyy-MM-dd HH:mm）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToStandardString(this DateTime dateTime)
	{
		return dateTime.ToString("yyyy-M-dd HH:mm");
	}

	/// <summary>
	/// 标准格式（yyyy-MM-dd HH:mm）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <param name="defaultValue">默认值</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToStandardString(this DateTime? dateTime, string defaultValue = "N/A")
	{
		if (!dateTime.HasValue)
			return defaultValue;
		return dateTime.Value.ToString("yyyy-M-dd HH:mm");
	}

	/// <summary>
	/// 转换为日期（yyyy-MM-dd）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <param name="defaultValue">默认值</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToDateString(this DateTime? dateTime, string defaultValue = "N/A")
	{
		if (!dateTime.HasValue)
			return defaultValue;
		return dateTime.Value.ToString("yyyy-MM-dd");
	}

	/// <summary>
	/// 转换为日期（yyyy-MM-dd）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToDateString(this DateTime dateTime)
	{
		return dateTime.ToString("yyyy-MM-dd");
	}

	/// <summary>
	/// 转换为日期（yyyy年MM月dd日）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToDateStringChinese(this DateTime dateTime)
	{
		return dateTime.ToString("yyyy年MM月dd日");
	}

	/// <summary>
	/// 转换为日期（yyyy年MM月dd日）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <param name="defaultValue">默认值</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToDateStringChinese(this DateTime? dateTime, string defaultValue = "N/A")
	{
		if (!dateTime.HasValue)
			return defaultValue;
		return dateTime.Value.ToString("yyyy年MM月dd日");
	}

	/// <summary>
	/// 转换为日期（yyyy.MM.dd）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <param name="defaultValue">默认值</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToDateStringWithDots(this DateTime? dateTime, string defaultValue = "N/A")
	{
		if (!dateTime.HasValue)
			return defaultValue;
		return dateTime.Value.ToString("yyyy.MM.dd");
	}

	/// <summary>
	/// 转换为日期时间（yyyy年MM月dd日 HH:mm）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <param name="defaultValue">默认值</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToDateTimeStringChinese(this DateTime? dateTime, string defaultValue = "N/A")
	{
		if (!dateTime.HasValue)
			return defaultValue;
		return dateTime.Value.ToString("yyyy年MM月dd日 HH:mm");
	}

	/// <summary>
	/// 没有虚位的日期格式（例如：2024年8月9日）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToDateStringWithoutPadding(this DateTime dateTime)
	{
		return $"{dateTime.Year}年{dateTime.Month}月{dateTime.Day}日";
	}

	/// <summary>
	/// 转换为日期时间（yyyy-MM-dd HH:mm:ss）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToDateTimeString(this DateTime? dateTime)
	{
		if (dateTime.HasValue)
			return dateTime.Value.ToString(" yyyy-MM-dd HH:mm:ss");
		else
			return "N/A";
	}

	/// <summary>
	/// 转换为日期时间（yyyy-MM-dd HH:mm:ss）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>格式化后的字符串</returns>
	public static string ToDateTimeString(this DateTime dateTime)
	{
		return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
	}

	/// <summary>
	/// 智能时间提示（例如：刚刚、几分钟前、几小时前、yyyy-MM-dd HH:mm）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>智能时间提示</returns>
	public static string ToSmartTimeString(this DateTime? dateTime)
	{
		if (dateTime.HasValue)
			return dateTime.Value.ToSmartTimeString();
		else
			return "N/A";
	}

	/// <summary>
	/// 智能时间提示（例如：刚刚、几分钟前、几小时前、yyyy-MM-dd HH:mm）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>智能时间提示</returns>
	public static string ToSmartTimeString(this DateTime dateTime)
	{
		string strTime = "";
		DateTime date1 = DateTime.Now;
		DateTime date2 = dateTime;
		TimeSpan dt = date1 - date2;

		// 相差天数
		int days = dt.Days;
		// 时间点相差小时数
		int hours = dt.Hours;
		// 相差总小时数
		double Minutes = dt.Minutes;
		// 相差总秒数
		int second = dt.Seconds;

		if (days == 0 && hours == 0 && Minutes == 0)
		{
			strTime = "刚刚";
		}
		else if (days == 0 && hours == 0)
		{
			strTime = Minutes + "分钟前";
		}
		else if (days == 0)
		{
			strTime = hours + "小时前";
		}
		else
		{
			strTime = dateTime.ToString("yyyy-M-dd HH:mm");
		}
		return strTime;
	}

	/// <summary>
	/// 转换为日期数字格式（例如：20180324）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>日期数字格式</returns>
	public static int ToDateNumber(this DateTime dateTime)
	{
		return dateTime.Year * 10000 + dateTime.Month * 100 + dateTime.Day;
	}

	/// <summary>
	/// 显示不可用提示
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>智能时间提示或不可用提示</returns>
	public static string ShowNotAvailable(this DateTime? dateTime)
	{
		if (!dateTime.HasValue)
			return "N/A";

		return dateTime.Value.ToSmartTimeString();
	}

	/// <summary>
	/// 日期转换为时间戳（单位：秒）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>时间戳</returns>
	public static long ToUnixTimeStamp(this DateTime dateTime)
	{
		DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
		return (long)(dateTime.AddHours(-8) - Jan1st1970).TotalSeconds;
	}

	/// <summary>
	/// 获取时间戳
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>时间戳</returns>
	public static long GetUnixTimeStamp(this DateTime dateTime)
	{
		return (dateTime.ToUniversalTime().Ticks - 621355968000000000) / 10000;
	}

	/// <summary>
	/// 时间戳转换为日期
	/// </summary>
	/// <param name="timeStamp">时间戳</param>
	/// <returns>日期</returns>
	public static DateTime FromUnixTimeStamp(this long timeStamp)
	{
		DateTime UnixTimeStampStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
		return UnixTimeStampStart.AddSeconds(timeStamp).ToLocalTime();
	}

	/// <summary>
	/// 转换为时间数字格式（例如：2018032412）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>时间数字格式</returns>
	public static long ToTimeNumber(this DateTime dateTime)
	{
		string dateStr = dateTime.ToString("yyyyMMdH");
		return long.Parse(dateStr);
	}

	/// <summary>
	/// 转换为数字格式（例如：2018032412）
	/// </summary>
	/// <param name="dateTime">日期</param>
	/// <returns>数字格式</returns>
	public static long ToNumber(this DateTime dateTime)
	{
		string dateStr = dateTime.ToString("yyyyMMddHH");
		return long.Parse(dateStr);
	}

	/// <summary>
	/// 获取上个月的最后一天
	/// </summary>
	/// <param name="dt">日期</param>
	/// <returns>上个月的最后一天</returns>
	public static DateTime GetLastDayOfPreviousMonth(this DateTime dt)
	{
		DateTime firstDayOfCurrentMonth = new DateTime(dt.Year, dt.Month, 1);
		DateTime lastDayOfPreviousMonth = firstDayOfCurrentMonth.AddDays(-1);
		return lastDayOfPreviousMonth;
	}

	/// <summary>
	/// 比较两个日期是否相等（仅比较日期部分）
	/// </summary>
	/// <param name="dateTime">日期1</param>
	/// <param name="dateTime2">日期2</param>
	/// <returns>如果日期相等，则为 true；否则为 false</returns>
	public static bool IsSameDate(this DateTime dateTime, DateTime dateTime2)
	{
		return dateTime.Date.Equals(dateTime2.Date);
	}
}

